﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Media.Imaging;
using System.Windows.Media.Animation;

using Bling.Core;
using Bling.WPF;
using Bling.WPF.Util;
using Bling.Slides;
using Bling.Util;
using Bling.Shaders;
using Bling.Graphics;

namespace Bling.Example {
  using Bling.Matrices;
  using Bling.WPF3D;
  using Bling.Shaders.DX;
  public class Example3 : Canvas, ICanStart, IHasGlobalPosition {
    //private static readonly Uri AutumnUri = "Resources/Autumn.jpg".MakePackUri(typeof(Example1));
    // These three lines are boiler plate to start and stop the rendering loop as this canvas is active/inactive.
    private readonly WPFHostBl Host;
    private PointBl OverlayPosition;
    public void Start() { Host.CurrentValue.Start(); }
    public void Stop() { Host.CurrentValue.Stop(); }
    // the real work begins.
    public void SetGlobalPosition(PointBl p) {
      OverlayPosition = p + 10d;
      //Overlay.LeftTop = p + 10d;// +Overlay.LeftTop;
    }
    public void UnsetGlobalPosition() {}
    public static GetProperty<Example3, Vecs.Vec4<double>> RotationAProperty = "RotationA".NewProperty<Example3, Vecs.Vec4<double>>(new Vecs.Vec4<double>() { X = 0, Y = 0, Z = 0, W = 1d });
    public QuaternionBl RotationA { get { return RotationAProperty[this]; } set { RotationA.Bind = value; } }

    public static GetProperty<Example3, Vecs.Vec4<double>> RotationBProperty = "RotationB".NewProperty<Example3, Vecs.Vec4<double>>(new Vecs.Vec4<double>() { X = 0, Y = 0, Z = 0, W = 1d });
    public QuaternionBl RotationB { get { return RotationBProperty[this]; } set { RotationB.Bind = value; } }

    public static GetProperty<Example3, Vecs.Vec2<double>> DeltaProperty = "Delta".NewProperty<Example3, Vecs.Vec2<double>>();
    public PointBl Delta { get { return DeltaProperty[this]; } set { Delta.Bind = value; } }

    public static GetProperty<Example3, Matrix<double, D4, D4>> MainTransformProperty = "MainTransform".NewProperty<Example3, Matrix<double, D4, D4>>();
    public MatrixBl<D4,D4> MainTransform { get { return MainTransformProperty[this]; } set { MainTransform.Bind = value; } }

    public Example3() {
      CanvasBl Canvas = this;
      Canvas.Background = Brushes.White;
      var OverlayContent = new CanvasBl() {
        Background = new ColorBl(1, 1, 1, .01),
      };
      new RectangleBl(OverlayContent) {
        LeftTop = 0,
        Size = OverlayContent.Size,
        Stroke = { Brush = Brushes.Green, Thickness = 5d }
      };


      //method 1:
      PointBl EllipseSize = new PointBl(400, 400);
      Func<PointBl, PointBl, DoubleBl, Point3DBl> TurnToVirtualSphere0 = (point, center, radius) => {
        var xy = (point - center) / radius;
        var l = xy.LengthSquared;
        var z = (l > 1).Condition(0, (1d - l).Sqrt);
        xy = (l > 1).Condition(xy / l.Sqrt, xy);
        return new Point3DBl(xy, z);
      };
      var Update =
        QuaternionBl.Assign<Vecs.Vec2<double>, Vecs.Vec2<double>>((p0, p1) => RotationA, (oldP0, newP0) => {
          PointBl oldP = oldP0; PointBl newP = newP0;
          oldP = new PointBl(oldP.X, EllipseSize.Y - oldP.Y);
          newP = new PointBl(newP.X, EllipseSize.Y - newP.Y);
          // figure out delta from center.
          var p0 = TurnToVirtualSphere0(oldP, EllipseSize / 2d, EllipseSize.X / 2d - 6);
          var p1 = TurnToVirtualSphere0(newP, EllipseSize / 2d, EllipseSize.X / 2d - 6);
          var axis = p0.Cross(p1);
          //axis = RotationA.Matrix.Transform(axis);
          var q2 = new QuaternionBl(axis, p0.Dot(p1).Acos);
          return (RotationA).Concat(q2);
        });
      Func<Vecs.Vec2<double>> PositionAt = null;
      LineBl CutLine2D;
      PointBl slope, t1, t2;

      MainTransform = MatrixBl<D4, D4>.Identity;
      Func<Point3DBl, Point3DBl> F3to2 = (p) => {//(0,1)=>(0, 510)
        var q = -1d + 2d * (new PointBl(p.X, 1 - p.Y));
        var t0 = (MainTransform).Transform(new Point3DBl(q, p.Z));//-1
        var t = t0.XY();
        t = (t + 1d) / 2d;
        return new Point3DBl(t.X * 510, (1 - t.Y) * 510, t0.Z);
      };

      Func<Point3DBl, Point3DBl> F2to3 = (p) => {//(0,510)=>(0, 1)
        var q0 = new PointBl(p.X / 510, 1 - p.Y / 510);
        var q = q0 * 2 - 1;
        var t0 = (MainTransform.Invert()).Transform(new Point3DBl(q, p.Z));
        var t = t0.XY();
        t = (t + 1d) / 2d;
        return new Point3DBl(t.X, (1 - t.Y), t0.Z);
      };

      {
        CutLine2D = new LineBl(OverlayContent) {
          //Visibility = Visibility.Hidden,
          ZIndex = 2,
          Stroke = { Brush = Brushes.White, Thickness = 4 },
          Opacity = 0.5,
          Start = new PointBl(250, 10),
          End = new PointBl(250, 500),
        };



        //t1 = p1.XY();
        //t2 = p2.XY();
        //t1 = t11.XY(); //right method, i think?
        //t2 = t22.XY();

        Point3DBl p1 = F3to2(new Point3DBl(CutLine2D.Start / new PointBl(510, 510), -1));
        Point3DBl p2 = F3to2(new Point3DBl(CutLine2D.End / new PointBl(510, 510), -1));
        //var t11 = F2to3(new Point3DBl(th1.CenterPosition, 0));
        //var t22 = F2to3(new Point3DBl(th2.CenterPosition, 0));
        Action AdjustCutLineStart = null, AdjustCutLineEnd = null;
        var CutLine232D = new LineBl(OverlayContent) {
          ZIndex = 2,
          IsHitTestVisible = false,
          Stroke = { Brush = Brushes.Orange, Thickness = 4 },
          Opacity = 0.75,
          Start = p1.XY(), // F3to2(t11).XY(),
          End = p2.XY(), // F3to2(t22).XY(),
        };
        var SetStart3D = PointBl.Assign<Vecs.Vec2<double>>((delta) => CutLine2D.Start, (delta) => {
          var point = (CutLine232D.Start + delta.Bl()).InsertZ(p1.Z);
          var q = (F2to3(point).XY() * new PointBl(510, 510));

          return q;
        });
        var th1 = new ThumbBl(OverlayContent) {
          CenterPosition = CutLine232D.Start, Background = Brushes.White, Size = new PointBl(15, 15), Opacity = 0.5, ZIndex = 100,
          CanDragG = (thumb0, delta) => { SetStart3D(delta.CurrentValue); AdjustCutLineStart(); },
          CanDrag = true
        };
        var SetEnd3D = PointBl.Assign<Vecs.Vec2<double>>((delta) => CutLine2D.End, (delta) => {
          var point = (CutLine232D.End + delta.Bl()).InsertZ(p2.Z);
          var q = (F2to3(point).XY() * new PointBl(510, 510));
          return q;
        });
        var th2 = new ThumbBl(OverlayContent) {
          CenterPosition = CutLine232D.End, Background = Brushes.White, Size = new PointBl(15, 15), Opacity = 0.5, ZIndex = 100,
          CanDragG = (thumb0, delta) => { SetEnd3D(delta.CurrentValue); AdjustCutLineEnd(); },
          CanDrag = true
        };
        var th3 = new ThumbBl(OverlayContent) {
          ZIndex = 100, LeftTop = th1.RightTop, Size = new PointBl(15, 15), Opacity = 0.5,
          Background = Brushes.Purple,
          CanDragG = (thumb0, delta) => {
            PointBl prev = CutLine2D.Start.CurrentValue;
            SetStart3D(delta.CurrentValue);
            AdjustCutLineStart();
            PointBl newDelta = CutLine2D.Start.CurrentValue;
            newDelta = newDelta - prev;
            PointBl newEnd0 = CutLine2D.End.CurrentValue;
            newEnd0 = newEnd0 + newDelta;
            CutLine2D.End.Now = newEnd0;
            AdjustCutLineEnd();
          },
          CanDrag = true,
        };


        var SetCutLineStart = PointBl.Assign(CutLine2D.Start, OverlayContent.MousePosition);
        var SetCutLineEnd = PointBl.Assign(CutLine2D.End, OverlayContent.MousePosition);
        var thumbA = new ThumbBl(OverlayContent) {
          ZIndex = 3, CenterPosition = CutLine2D.Start,
          Background = Brushes.White,
          CanDragG = (thumb0, delta) => {
            var change = CutLine2D.Start + delta;
            change = (change.X > change.Y).Condition(new PointBl(change.X, 10), new PointBl(10, change.Y));
            CutLine2D.Start.Now = change.Max(new PointBl(10, 10));
          },
          CanDrag = true,
        };
        var thumbB = new ThumbBl(OverlayContent) {
          ZIndex = 3, LeftTop = thumbA.RightTop,
          Background = Brushes.Red,
          CanDragG = (thumb0, delta) => {
            var change = CutLine2D.Start + delta;
            change = (change.X > change.Y).Condition(new PointBl(change.X, 10), new PointBl(10, change.Y));
            change = change.Max(new PointBl(10, 10));
            var diff = change - CutLine2D.Start.Now;
            CutLine2D.Start.Now = change;
            var newEnd0 = CutLine2D.End.Now + diff;
            CutLine2D.End.Now = newEnd0;
          },
          CanDrag = true,
        };

        AdjustCutLineStart = PointBl.Assign(CutLine2D.Start, () => {
          var delta = CutLine2D.End - CutLine2D.Start;
          var mY = (delta.Y / delta.X) * CutLine2D.Start.X * -1 + CutLine2D.Start.Y;
          var mX = (delta.X / delta.Y) * CutLine2D.Start.Y * -1 + CutLine2D.Start.X;
          var result = (mX.IsNaN | mX < 10 | mX > 510).Condition(CutLine2D.Start, new PointBl(mX, 10));
          result = (mY.IsNaN | mY < 10 | mY > 510).Condition(result, new PointBl(10, mY));
          //new ThumbBl(OverlayContent) { CenterPosition = result, Background = Brushes.Blue };
          return result;

        });
        AdjustCutLineEnd = PointBl.Assign(CutLine2D.End, () => {
          var delta = CutLine2D.End - CutLine2D.Start;
          var mY = (delta.Y / delta.X) * (510 - CutLine2D.End.X) + CutLine2D.End.Y;
          var mX = (delta.X / delta.Y) * (510 - CutLine2D.End.Y) + CutLine2D.End.X;
          var result = (mX.IsNaN | mX < 0 | mX > 510).Condition(CutLine2D.Start, new PointBl(mX, 500));
          result = (mY.IsNaN | mY < 0 | mY > 510).Condition(result, new PointBl(500, mY));
          //new ThumbBl(OverlayContent) { CenterPosition = result, Background = Brushes.Yellow };
          return result;
        });
        OverlayContent.OnMouseDown = (x, y) => {
          y.Handled = true;
          SetCutLineStart();
          SetCutLineEnd();
          CutLine2D.Visibility = Visibility.Visible;
          var Going = true;
          Mouse.Capture(OverlayContent.CurrentValue);
          OverlayContent.OnMouseMove = (x0, y0) => {
            if (!Going) return false;
            y0.Handled = true;
            SetCutLineEnd();
            return true;
          };
          OverlayContent.OnMouseUp = (x0, y0) => {
            Going = false;
            y0.Handled = true;
            SetCutLineEnd();
            Mouse.Capture(OverlayContent.CurrentValue, CaptureMode.None);
            AdjustCutLineStart();
            AdjustCutLineEnd();
            return false;
          };

          return true;
        };
      }
      EllipseBl VirtualSphere = new EllipseBl(OverlayContent) {
        Size = EllipseSize,
        CenterPosition = OverlayContent.CenterSize,
        Fill = new ColorBl(1, 1, 1, 0.01),
        ZIndex = 10,
        Stroke = { Brush = Brushes.White, Thickness = 4 },
        OnMouseDown = (x, y) => {
          if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) {
            y.Handled = false;
            return true;
          }

          y.Handled = true;
          var oldP = PositionAt();
          var IsOut = false;
          //x.OnMouseLeave = (x0, y0) => { IsOut = true; return false; };
          x.OnMouseUp = (x0, y0) => { IsOut = true; return false; };
          System.Windows.Input.Mouse.Capture(x.CurrentValue);
          x.OnMouseMove = (x0, y0) => {
            if (IsOut || y0.LeftButton == System.Windows.Input.MouseButtonState.Released) {
              System.Windows.Input.Mouse.Capture(x.CurrentValue, System.Windows.Input.CaptureMode.None);
              return false;
            }
            var newP = PositionAt();
            Update(oldP, newP);
            oldP = newP;
            return true;
          };
          return true;
        },
      };


      PositionAt = VirtualSphere.MousePosition.AsFunc;
      QuaternionBl WholeRotate = RotationA;
      PointBl newStart, newEnd;
      {
        newStart = (CutLine2D.Start.Y < CutLine2D.End.Y).Condition(CutLine2D.End, CutLine2D.Start);
        newEnd = (CutLine2D.Start.Y < CutLine2D.End.Y).Condition(CutLine2D.Start, CutLine2D.End);

        //newStart = ((t1.Y < t2.Y).Condition(t2, t1));
        //newEnd =  ((t1.Y < t2.Y).Condition(t1, t2));

        slope = (newEnd - newStart).Normalize;

        newStart /= new PointBl(510, 510);
        newEnd /= new PointBl(510, 510);
      }

      // first, create some sliders to control the simulation.
      var slider = new LabelSliderBl(this) { LabelName = "Cut", Minimum = 0, Maximum = 1, Value = 0 };
      var CutRotateSlider = slider;
      var HideRed = new LabelSliderBl(this) { LabelName = "Red", LeftTop = CutRotateSlider.LeftBottom, Minimum = 0, Maximum = 1, Value = 0, Width = slider.Width };
      var HideGreen = new LabelSliderBl(this) { LabelName = "Green", LeftTop = HideRed.LeftBottom, Minimum = 0, Maximum = 1, Value = 0, Width = slider.Width };
      var HideBlue = new LabelSliderBl(this) { LabelName = "Blue", LeftTop = HideGreen.LeftBottom, Minimum = 0, Maximum = 1, Value = 0, Width = slider.Width };


      // world matrix specifies where a render object will go in the world. Just set it to the default for now.
      MatrixBl<D4, D4> ScaleDown;

      int DIM;
      {
        var canvasD = new CanvasBl() {
          Width = 400d,
        };
        var dimSlider = new SliderBl(canvasD) {
          Minimum = 5, Maximum = 40, Value = 20, Width = canvasD.Width,
          LeftTop = 0d,
        };
        var button = new ButtonBl(canvasD) {
          LeftTop = dimSlider.LeftBottom, Content = "Close at DIM = " + ((IntBl) dimSlider.Value).ToStringBl(),
        };
        canvasD.Height = dimSlider.Height + button.Height;
        var dlg = new WindowBl() {
          Content = canvasD, SizeToContent = SizeToContent.WidthAndHeight, ShowInTaskbar = false,
        };
        button.Click = () => dlg.CurrentValue.Close(); 

        dlg.CurrentValue.ShowDialog();
        DIM = (int) dimSlider.Value.CurrentValue;
      }

      var Sz = (1d / ((double)DIM));
      ScaleDown = (((Point3DBl)Sz)).Scale(new Point3DBl(-1d, -1d, -1d));


      // represents where our eye is in the world.
      Point3DBl Center = new Point3DBl(0, 0, 0);
      //Point3DBl Center = new Point3DBl(0,0,0); // new Point3DBl(moveX.Value, moveY.Value, 0);

      // Configure a WPF perspective camera.
      PerspectiveCameraCl Camera = new PerspectiveCameraCl() {
        Position = Center + new Point3DBl(0, 0, -4),
        //((rotateX0.Value + 90).ToDegrees().ToPoint * moveZ.Value).InsertY(0),
        Direction = { Look = Center },
        FieldOfView = .25.PI().AsDegrees,
      };

      // create a new device in which to hold rendering information
      RenderDevice Device = new RenderDevice();
      var light = new DirectionalLightBl() {
        Direction = new Point3DBl(.5, .5, 10d).Normalize,
        Color = Colors.White,
      };
      var diffuse = new DiffuseMaterialCl() { Factor = .8, Ambient = { Factor = .5 } };
      var Sample = new CubeSample();

      var rand = new Random();


      Color[] CubeColors = new Color[DIM * DIM * DIM];
      {
        Action<int, double, double, Func<Color, double, Color>> G = (Count, Min, Max, Fc) => {
          for (int i = 0; i < Count; i++) {
            // try to find a coordinate.
            int x = rand.Next(DIM);
            int y = rand.Next(DIM);
            int z = rand.Next(DIM);
            var sz = Min + (Max - Min) * rand.NextDouble();
            for (int xi = 0; true; xi++) {
              var dxi = ((double)xi) / ((double)DIM);
              if (dxi > sz) break;
              for (int yi = 0; true; yi++) {
                var dyi = ((double)yi) / ((double)DIM);
                if (dyi > sz) break;
                for (int zi = 0; true; zi++) {
                  var dzi = ((double)zi) / ((double)DIM);
                  if (dzi > sz) break;

                  var v = new Vector3D(dxi, dyi, dzi);
                  var length = 1d - v.Length / sz;
                  if (length <= 0) continue;
                  Action<int, int, int> F = (xj, yj, zj) => {
                    if (xj >= DIM || xj < 0) return;
                    if (yj >= DIM || yj < 0) return;
                    if (zj >= DIM || zj < 0) return;
                    var jdx = xj + yj * DIM + zj * DIM * DIM;
                    if (CubeColors[jdx] == null) CubeColors[jdx] = Color.FromScRgb(1, 0, 0, 0);
                    var clr = CubeColors[jdx];
                    clr = Fc(clr, length);
                    CubeColors[jdx] = clr;
                  };
                  F(x + xi, y + yi, z + zi);
                  F(x + xi, y + yi, z - zi);
                  F(x + xi, y - yi, z + zi);
                  F(x + xi, y - yi, z - zi);

                  F(x - xi, y + yi, z + zi);
                  F(x - xi, y + yi, z - zi);
                  F(x - xi, y - yi, z + zi);
                  F(x - xi, y - yi, z - zi);
                }
              }
            }
          };
        };
        G(50, .03, .15, (clr, len) => {
          clr.ScB = (float)len;
          return clr;
        });
        G(10, .1, .2, (clr, len) => {
          var total = len + clr.ScB;
          clr.ScG = (float)(len / total);
          return clr;
        });
        for (int xi = 0; xi < DIM; xi++) {
          for (int yi = 0; yi < DIM; yi++) {
            for (int zi = 0; zi < DIM; zi++) {
              var jdx = xi + yi * DIM + zi * DIM * DIM;
              var clr = CubeColors[jdx];
              if (clr == null) CubeColors[jdx] = Colors.Red;
              else {
                var total = Math.Min(clr.ScB + clr.ScG, 1d);
                clr.ScR = (float)(1d - total);
                CubeColors[jdx] = clr;
              }
            }
          }
        }
      }


      Device.Render(Sample.Count, DIM * DIM * DIM, (idx, jdx, vertex) => {
        IntBl x = (jdx % (DIM));
        IntBl y = (jdx / (DIM)) % DIM;
        IntBl z = (jdx / (DIM)) / DIM;
        var Translate = MatrixBl<D4, D4>.Identity;
        Translate = (new Point3DBl(x, y, z) * (Sz * 2)).Translate();
        var iy = y / (DoubleBl)(DIM - 1).Bl();
        var ix = x / (DoubleBl)(DIM - 1).Bl();
        var CutAngle = CutRotateSlider.Value.PI() * .25d * (ix >= (newStart.X - (iy - 1 + newStart.Y) / slope.Y * slope.X)).Condition(+1d.Bl(), -1d.Bl());
        var Cut = (new QuaternionBl(new Point3DBl(slope.X, -slope.Y, 0), CutAngle));
        DoubleBl Dx = newEnd.X * 2 - 1,//Sz * (DIM / 2) * (-1d + 2d * .5 /*PivotSliderA.Value */) * 4,
                 Dy = 1 - newEnd.Y * 2, Dz = 1;//(-1d + 2d * 1d /*PivotSliderB.Value*/);
        var RotationOnly =
           (new Point3DBl(-Dx, -Dy, -Dz)).Translate() * Cut.Matrix *
           (new Point3DBl(+Dx, +Dy, +Dz)).Translate() * WholeRotate.Matrix;
        var Total = ScaleDown * Translate * RotationOnly;
        vertex.Position = Sample[idx] * ((Total) * Camera);
        MainTransform = WholeRotate.Matrix * Camera.Matrix;
        var worldPos = (Point3DBl)(Sample[idx] * (Total));
        // do not including any translation for normal!
        var normal = (Point3DBl)(Sample.Normals.Table(idx / 4) * Cut.Matrix * WholeRotate.Matrix).Normalize;
        // don't bother with lighitng right now.
        ColorBl clr = new Bling.DSL.TableExpr2<Color>(CubeColors, jdx); //  
        //new ColorBl(x / 2, y, z) / new ColorBl(DIM / 2, DIM, DIM);
        clr = diffuse.Apply(light + new AmbientLightBl() { Color = Colors.White })[worldPos, normal, Camera.Position][clr];
        vertex.Color = new ColorBl(clr.ScRGB, (1d - clr.ScR * HideRed.Value).Min(1d - clr.ScB * HideBlue.Value).Min(1d - clr.ScG * HideGreen.Value));

      }, Sample.IndexBuffer);


      // this will actually cause rendering to occur in a WPF host. 
      var Host0 = new Bling.Shaders.DX.WPFHostBl(this, new PointBl(500, 500), Device) {
        LeftTop = 10d,
        ZIndex = 0,
        IsHitTestVisible = false,
      };
      var TriggerRectA = new CanvasBl(Canvas) {
        LeftTop = 5d,
        Size = new PointBl(510, 510),
        ZIndex = 2,
        Background = Colors.Blue,
      };

      // so start and stop work.
      Host = Host0;
      // sliders go beneath the host.
      slider.LeftTop = Host0.LeftBottom;
      slider.Width = 510;

      WindowBl Overlay = null;

      var resetA = new ButtonBl(Canvas) {
        LeftBottom = new PointBl(0, Canvas.Height),
        Content = "Reset",
        Click = QuaternionBl.Assign(RotationA, QuaternionBl.Identity),

      };
      var snapA = new ButtonBl(Canvas) {
        Content = "Snap",
        LeftTop = resetA.RightTop,
        Click = QuaternionBl.Assign(RotationA, new QuaternionBl(RotationA.Axis.Round, 0
          /*(((RotationA.Angle.Radians / (Math.PI * 2d)) * 4d).Round / 4d).PI2()*/)),

      };

      TriggerRectA.OnMouseEnter = (x, y) => {
        if (((object)Overlay) == null) {
          y.Handled = true;
          Overlay = new WindowBl() {
            WindowStyle = WindowStyle.None,
            AllowsTransparency = true,
            Background = Brushes.Transparent,
            Content = OverlayContent,
            //SizeToContent = SizeToContent.WidthAndHeight,
            Size = new PointBl(500, 500) + 10d,
            Topmost = true,
            LeftTop = OverlayPosition - 5d,
          };
          Overlay.OnMouseLeave = (x0, y0) => {
            if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) return true;
            if (((object)Overlay) != null) {
              Overlay.Content = new LabelBl();
              Overlay.CurrentValue.Close();
              Overlay = null;
            }
            return false;
          };

          Overlay.CurrentValue.Show();
        }
        return true;
      };
      Canvas.OnMouseEnter = (x, y) => {
        if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) return true;
        if (((object)Overlay) != null) {
          y.Handled = true;
          Overlay.Content = new LabelBl();
          Overlay.CurrentValue.Close();
          Overlay = null;
        }
        return true;
      };

    }
  }
}
